package com.zhl.study.threadWait;

import com.zhl.study.getThreadResult.ResultThread;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @description java中实现线程的等待
 * wait()、notify()、notifyAll() 和 join() 这几种方式都可以用于实现线程之间的等待和通知,但它们的用途和使用场景有所不同,主要区别如下:
 *      wait()、notify() 和 notifyAll()
 *          这三个方法是 Object 类的方法,用于线程之间的通信和等待。
 *          wait() 方法会使当前线程进入等待状态,并释放对象的监视器(锁)。
 *          notify() 方法会唤醒单个等待该对象监视器的线程。
 *          notifyAll() 方法会唤醒所有等待该对象监视器的线程。
 *          这几个方法需要在同步代码块中使用,以确保线程安全。
 *          通常配合 while 循环使用,以防止虚假唤醒。
 *      join()
 *          join() 是 Thread 类的方法,用于让当前线程等待指定线程终止。
 *          它不会释放任何锁资源,也不需要在同步代码块中使用。
 *          join() 方法可以让主线程等待子线程完成后再继续执行,常用于获取子线程的执行结果。
 * 通常配合 while 循环使用,以防止虚假唤醒。
 * @Author: z156940l@outlook.com
 * @className ThreadWait
 * @Date: 2024/5/23 10:48
 */
@Slf4j
public class ThreadWait {

    /**
     * 使用join()方法
     *
     * @throws InterruptedException
     */
    public static void testJoin() throws InterruptedException {
        Thread t1 = new Thread(new ResultThread());
        t1.start();

        Thread t2 = new Thread(new ResultThread());
        t2.start();

        // 主线程等待t1执行完毕
        t1.join();

        // t1执行完后,主线程再等待t2执行完毕
        t2.join();
        log.info("Both workers finished");
    }

    public static void main(String[] args) {
        waitNotify1();
    }
    /**
     * 使用等待/通知机制
     */
    public static void waitNotify1() {
        Object lock = new Object();
        AtomicBoolean isWorkerDone = new AtomicBoolean(false);

        Thread worker = new Thread(() -> {
            // 执行一些工作
            log.info("worker thread is start...");
            synchronized (lock) {
                isWorkerDone.set(true);
                lock.notifyAll(); // 通知其他线程工作已完成
            }
        });

        worker.start();

        // 主线程等待worker线程完成工作
        synchronized (lock) {
            log.info("main thread is check...");
            while (!isWorkerDone.get()) {
                log.info("main thread is start...");
                try {
                    lock.wait(); // 等待通知
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        log.info("Worker finished");
    }

    private static Object lock = new Object();
    private static boolean isDataReady = false;
    /**
     * 使用等待/通知机制
     */
    public static void waitNotify2(){
        Thread producer = new Thread(() -> {
            // 模拟生产数据的过程
            try {
                log.info("producer is start...");
                Thread.sleep(2000);
                log.info("producer is sleep end...");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            synchronized (lock) {
                isDataReady = true;
                lock.notifyAll(); // 通知等待的线程
            }
        });

        Thread consumer = new Thread(() -> {
            log.info("consumer is start...");
            synchronized (lock) {
                while (!isDataReady) {
                    try {
                        log.info("consumer is get lock...");
                        lock.wait(); // 等待数据就绪
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                log.info("Data is ready, consumer can consume it.");
            }
        });

        consumer.start();
        producer.start();
    }

    /**
     * 使用CountDownLatch
     */
    public static void testCountDownLatch() {
        CountDownLatch latch = new CountDownLatch(1);

        Thread t1 = new Thread(() -> {
            try {
                log.info("t1 thread is work...");
                // 执行工作
                latch.await(); // 工作线程执行任务
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread t2 = new Thread(() -> {
            try {
                log.info("t2 thread is work...");
                // 执行工作
                latch.await(); // 工作线程执行任务
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        t1.start();
        t2.start();

        // 主线程先执行任务
        log.info("main thread is work...");
        latch.countDown(); // 计数为0

        log.info("Both workers finished");
    }

    /**
     * 使用CyclicBarrier
     */
    public static void testCyclicBarrier() {
        // 创建一个CyclicBarrier实例,需要等待3个线程到达barriers
        CyclicBarrier barrier = new CyclicBarrier(3, new BarrierAction());

        // 创建并启动3个工作线程
        Thread t1 = new Thread(new Worker(barrier), "Worker-1");
        Thread t2 = new Thread(new Worker(barrier), "Worker-2");
        Thread t3 = new Thread(new Worker(barrier), "Worker-3");

        t1.start();
        t2.start();
        t3.start();
    }
}
